package com.tengfei.blogsystem.service.impl;

import com.tengfei.blogsystem.dao.ImageDao;
import com.tengfei.blogsystem.pojo.Images;
import com.tengfei.blogsystem.pojo.User;
import com.tengfei.blogsystem.response.ResponseResult;
import com.tengfei.blogsystem.response.ResponseState;
import com.tengfei.blogsystem.service.IImageService;
import com.tengfei.blogsystem.service.IUserService;
import com.tengfei.blogsystem.utils.Constants;
import com.tengfei.blogsystem.utils.SnowFlakeIdWorker;
import com.tengfei.blogsystem.utils.TextUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.transaction.Transactional;
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @version v1.0
 * @author} feige
 * @date 2021-10-21-20:36
 * @description
 */
@Slf4j
@Service
@Transactional
public class ImageServiceImpl implements IImageService {

    public static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");

    @Value("${blog.image.save-path}")
    public String IMAGE_PATH;
    @Value("${blog.image.max-size}")
    public long MAX_SIZE;

    @Autowired
    private SnowFlakeIdWorker idWorker;
    @Autowired
    private IUserService userService;
    @Autowired
    private ImageDao imageDao;


    @Override
    public ResponseResult uploadImage(HttpServletRequest request, HttpServletResponse response, MultipartFile file) {
        // 判断file是否为空
        if (file == null) {
            return new ResponseResult(ResponseState.ERROR, "上传内容为空");
        }
        // 只支持图片类中上次，jpg，png，gif
        String fileType = file.getContentType();
        if (TextUtils.isEmpty(fileType)) {
            return new ResponseResult(ResponseState.ERROR, "文件格式错误");
        }
        log.info("type-->" + fileType);
        String originalFilename = file.getOriginalFilename();
        String type = null;
        if (fileType.equals("image/jpg") && originalFilename.endsWith("jpg")) {
            type = "jpg";
        } else if (fileType.equals("image/png") && originalFilename.endsWith("png")) {
            type = "png";
        } else if (fileType.equals("image/gif") && originalFilename.endsWith("gif")) {
            type = "gif";
        } else {
            return new ResponseResult(ResponseState.ERROR, "请上传正确的图片类型");
        }
        String name = file.getName();
        log.info("name==>" + name);
        log.info("originalFilename==>" + originalFilename);
        // 限制文件大小
        long size = file.getSize();
        if (size > MAX_SIZE) {
            return new ResponseResult(ResponseState.ERROR, "请上传" + MAX_SIZE / 1024 / 1024 + "Mb内的图片");
        }
        // 文件保存规则
        long currentMillis = System.currentTimeMillis();
        String currentDate = simpleDateFormat.format(currentMillis);
        String datePath = IMAGE_PATH + File.separator + currentDate;
        File datePathFile = new File(datePath);
        if (!datePathFile.exists()) {
            datePathFile.mkdirs();
        }
        String targetName = String.valueOf(idWorker.nextId());
        String targetPath = datePath + File.separator + type + File.separator + targetName + "." + type;
        File targetPathFile = new File(targetPath);
        if (!targetPathFile.getParentFile().exists()) {
            targetPathFile.mkdirs();
        }
        // 保存文件，同步保存信息到数据库
        try {
            if (targetPathFile.exists()) {
                targetPathFile.createNewFile();
            }
            log.info("targetFile==>" + targetPathFile);
            // 保存文件
            file.transferTo(targetPathFile);
            // 保存信息到数据库
            String resultPath = currentMillis + "_" + targetName + "." + type;
            Images images = new Images();
            images.setId(targetName);
            images.setContentType(type);
            images.setCreateTime(new Date());
            images.setUpdateTime(new Date());
            images.setPath(targetPathFile.getPath());
            images.setName(originalFilename);
            images.setUrl(resultPath);
            images.setState("1");
            images.setUserId(userService.checkUser(request, response).getId());
            imageDao.save(images);
            // 返回信息
            Map<String, String> map = new HashMap<>();
            map.put("id", resultPath);
            map.put("name", originalFilename);
            // 上传成功
            return new ResponseResult(ResponseState.SUCCESS, "上传成功", map);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return new ResponseResult(ResponseState.ERROR, "上传失败，请稍后再试");
    }

    @Override
    public void getImage(HttpServletResponse response, String imageId) {
        // 设置响应头
        response.setContentType("image/png");
        String[] paths = imageId.split("_");
        // 该图片上传时的时间戳
        String timeMillis = paths[0];
        String imageName = paths[1];
        // 类型
        String type = imageName.split("\\.")[1];
        // 路径
        String targetPath = IMAGE_PATH + File.separator + simpleDateFormat.format(Long.parseLong(timeMillis)) + File.separator + type + File.separator + imageName;
        log.info("targetPath==>" + targetPath);
        File file = new File(targetPath);
        OutputStream os = null;
        InputStream is = null;
        try {
            os = response.getOutputStream();
            is = new FileInputStream(file);
            byte[] bf = new byte[1024];
            int len = 0;
            while ((len = is.read(bf)) != -1) {
                os.write(bf, 0, len);
            }
            os.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (is != null) {
                    is.close();
                }
                if (os != null) {
                    os.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public ResponseResult listImage(HttpServletRequest request, HttpServletResponse response, int page, int size) {
        // 查询用户
        User user = userService.checkUser(request, response);
        if (user == null) {
            return new ResponseResult(ResponseState.NOT_LOGIN);
        }
        String userId = user.getId();
        // 分页查询
        if (page < Constants.PageValue.DEFAULT_PAGE) {
            page = Constants.PageValue.DEFAULT_PAGE;
        }
        if (size < Constants.PageValue.MIN_SIZE) {
            size = Constants.PageValue.MIN_SIZE;
        }
        // 排序
        Sort sort = Sort.by(Sort.Direction.DESC, "createTime");
        Pageable pageable = PageRequest.of(page - 1, size, sort);
        Page<Images> categories = imageDao.findAll(new Specification<Images>() {
            @Override
            public Predicate toPredicate(Root<Images> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                Predicate byUserId = cb.equal(root.get("userId").as(String.class), userId);
                Predicate byState = cb.equal(root.get("state").as(String.class), "1");
                return cb.and(byUserId, byState);
            }
        }, pageable);
        return new ResponseResult(ResponseState.SUCCESS, "查询图片列表成功", categories);
    }

    @Override
    public ResponseResult deleteImage(String imageId) {
        int result = imageDao.deleteImageByUpdateState(imageId);
        if (result > 0) {
            return new ResponseResult(ResponseState.SUCCESS, "删除成功");
        }
        return new ResponseResult(ResponseState.ERROR, "删除失败");
    }
}
